package algo3c3g3.view;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import algo3c3g3.model.*;
import algo3c3g3.controller.*;
import java.util.*;

/**
 * Area donde se dibujan todos los elementos del juego.
 */
public class GameArea extends JPanel implements Observer
{
    private World world;
    private ActionController controller;
    
    private static final int
            SCREEN_OFFSET_X = 10,
            SCREEN_OFFSET_Y = 10,
            IMAGE_SIZE = 16;
    
    private int width, height;
    
    private Sprites sprites = new Sprites();
    
    
    /**
     * @param level Modelo de datos asociado.
     * @param controller Controlador del modelo asociado.
     */
    public GameArea(Level level, Controller controller)
    {
        world = level.getWorld();
        this.controller = controller.getActionController();
        
        width = world.getMap().getWidth() * IMAGE_SIZE + SCREEN_OFFSET_X * 2;
        height =  world.getMap().getHeight() * IMAGE_SIZE + SCREEN_OFFSET_Y * 2;
        
        setPreferredSize(new Dimension(width, height));
        setMinimumSize(new Dimension(width, height));
        setBounds(0, 0, width, height);
        
        addMouseListener(new MouseAdapter()
        {
            @Override
            public void mouseClicked(MouseEvent e)
            {
                GameArea.this.controller.setUnitAction(pixelToCoord(e.getX(), e.getY()));
                GameArea.this.repaint();
            }
        });
        
        world.addObserver(this);
    }
    
    @Override
    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        
        paintDoors(g);
        paintMap(world.getMap(), g, sprites);
        paintUnits(world, g, sprites);
    }
    
    public void update(Observable o, Object arg)
    {
        repaint();
    }
    
    // Dibuja el mapa a partir del modelo.
    private synchronized void paintMap(WorldMap map, Graphics g, Sprites sprites)
    {
        int currX = SCREEN_OFFSET_X, currY = SCREEN_OFFSET_Y;
        
        BufferedImage img = null;
        
        
        for(int y = 0; y < map.getHeight(); y++)
        {
            for(int x = 0; x < map.getWidth(); x++)
            {
                img = sprites.loadSprite(ImagePaths.getMaterialImage(map.blockAt(x, y).getMaterial()));
                g.drawImage(img, currX, currY, this);
                currX += IMAGE_SIZE;
            }
            
            currX = SCREEN_OFFSET_X;
            currY += IMAGE_SIZE;
        }
    }
    
    // Dibuja la entrada y salida.
    private void paintDoors(Graphics g)
    {
        Coord c = null;
        
        BufferedImage img = sprites.loadSprite(ImagePaths.getDoorImage(ImagePaths.ENTRANCE));
        c = world.getEntrancePosition();
        g.drawImage(img, coordToPixel(c.getXCoord()), coordToPixel(c.getYCoord()), this);
        
        img = sprites.loadSprite(ImagePaths.getDoorImage(ImagePaths.EXIT));
        c = world.getExitPosition();
        g.drawImage(img, coordToPixel(c.getXCoord()), coordToPixel(c.getYCoord()), this);
    }
    
    // Dibuja las unidades
    private synchronized void paintUnits(World world, Graphics g, Sprites sprites)
    {        
        java.util.List<Unit> units = world.getAllUnits();
        
        Iterator<Unit> i = units.iterator();
        
        while(i.hasNext())
        {
            Unit u = i.next();
            
            if(u.isAlive())
            {
                BufferedImage img = sprites.loadSprite(ImagePaths.getActionImage(u));
                
                g.drawImage(img,
                           coordToPixel(u.getXPosition()),
                           coordToPixel(u.getYPosition()),
                           this);
            }
        }
    }
    
    private Coord pixelToCoord(int x, int y)
    {
        return new Coord((x - SCREEN_OFFSET_X) / IMAGE_SIZE,
                         (y - SCREEN_OFFSET_X) / IMAGE_SIZE);
    }
    
    private int coordToPixel(int coord)
    {
        return (coord * IMAGE_SIZE) + SCREEN_OFFSET_X;
    }
}
